﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using MongoDB.Driver;
using Sustainalytics.DataLayer.Tests.Shared;
using Sustainalytics.Entities;
using System;
using System.IO;
using System.Linq;

namespace Sustainalytics.DataLayer.Shared.Tests
{
    internal class TestHelper : IEntity, IFileContent
    {
        public Guid Id { get; set; }
        public ReportType ReportType { get; set; }
        public Guid CompanyId { get; set; }

        public int FileType { get; set; }
        public TimeSpan RenderDuration { get; set; }

        public string FileName { get; set; }
        public string MimeType { get; set; }
        public byte[] FileContent { get; set; }
    }

    [TestClass()]
    public class RepositoryCollectionWithFileTests
    {
        private string dbCnx = "mongodb://localhost:27017/ClientPlatform_Tests";
        private string databaseName = "ClientPlatform_Tests";
        private string collectionName = typeof(Helper).Name;

        private IMongoDatabase database = null;

        [TestInitialize]
        public void Initialize()
        {
            var mongoClient = new MongoClient(dbCnx);
            database = mongoClient.GetDatabase(databaseName);
            database.GetCollection<TestHelper>(collectionName).DeleteMany(_ => true);
        }

        [TestCleanup]
        public void Cleanup()
        {
        }

        private bool StreamsAreIdentical(Stream a, Stream b)
        {
            if (a.Length != b.Length)
                return false;

            a.Position = 0;
            b.Position = 0;

            var buffer1 = new byte[65535];
            var buffer2 = new byte[65535];

            for (var i = 0; i < a.Length; i++)
            {
                var found1 = a.Read(buffer1, 0, 65535);
                var found2 = b.Read(buffer2, 0, 65535);

                if (found1 != found2)
                    return false;

                for (var j = 0; j < found1; j++)
                    if (buffer1[j] != buffer2[j])
                        return false;
            }
            return true;
        }

        [TestMethod()]
        public void ReadTest()
        {
            var input = new TestHelper
            {
                Id = Guid.NewGuid(),
                CompanyId = Guid.NewGuid(),
                FileContent = new byte[8192],
                FileName = "abc",
                FileType = 1,
                MimeType = "application/pdf",
                RenderDuration = TimeSpan.FromMilliseconds(100)
            };
            Random rnd = new Random();
            rnd.NextBytes(input.FileContent);

            var rep = new RepositoryCollectionWithFile<TestHelper>(dbCnx);
            rep.Create(input);
            var output = rep.Read(input.Id);

            Assert.AreEqual(output.CompanyId, input.CompanyId, "document store/read fails");
            Assert.IsTrue(StreamsAreIdentical(new MemoryStream(output.FileContent), new MemoryStream(input.FileContent)), "file store fails");
        }

        [TestMethod]
        public void ReadAllWhereEqual_WithExpression_Test()
        {
            var input = new TestHelper
            {
                Id = Guid.NewGuid(),
                CompanyId = Guid.NewGuid(),
                FileContent = new byte[8192],
                FileName = "abc",
                FileType = 1,
                MimeType = "application/pdf",
                RenderDuration = TimeSpan.FromMilliseconds(100)
            };
            var rnd = new Random();
            rnd.NextBytes(input.FileContent);

            var rep = new RepositoryCollectionWithFile<TestHelper>(dbCnx);
            rep.Create(input);

            var output = rep.ReadAllWhereFieldEqualsValue(x => x.CompanyId, input.CompanyId).FirstOrDefault();

            Assert.AreEqual(output.CompanyId, input.CompanyId, "document store/read fails");
            Assert.IsTrue(StreamsAreIdentical(new MemoryStream(output.FileContent), new MemoryStream(input.FileContent)), "file store fails");
        }
    }
}
